/**
 * Copyright 2013 Douglas Lacher
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author Douglas Lacher <doug.lacher@gmail.com>
 */

package com.devioustoast.andmoco;

import java.util.ArrayList;
import java.util.List;

import android.util.Log;

/**
 * A Move represents a physical movement by the robot, such as moving a leg.  Each movement
 * may contain one or more movements.
 *
 * @author Douglas Lacher <doug.lacher@gmail.com>
 */
public class Move implements Runnable {

  public static final String LOG_TAG = "Move";

  public String name;

  /**
   * A List of the movements that comprise this movement.  Iterate over this to execute movements.
   */
  public List<Runnable> movements = new ArrayList<Runnable>();

  /**
   * A default constructor to create an empty move.  This is useful primarily for programmatic
   * building of the object.
   */
  public Move() { }

  /**
   * Creates a Move with no movements.
   *
   * @param name the name of this move.
   */
  public Move(String name) {
    this.name = name;
  }

  /**
   * This constructor moves a single servo.
   *
   * @param name the name of this move.
   * @param servo the servo number.
   * @param microseconds the new position to which the servo should move.  Position is measured in
   *        micro-seconds (as a pulse-width) and has a range dependent on the servos being used.
   * @param relative set true to treat the new position as a relative position.  Set false to treat
   *        it as an absolute position.
   * @param waitTimeMs time in milliseconds to wait after this move.
   */
  public Move(String name, Servo servo, int newPosition, boolean relative, int waitTimeMs) {
    this.name = name;
    movements.add(new Movement(servo, newPosition, relative, waitTimeMs));
  }

  /**
   * Creates a Move with a single Movement (and therefore one Servo).
   *
   * @param name the name of this move.
   * @param movement a Movement object describing which servo to move.
   */
  public Move(String name, Runnable movement) {
    this.name = name;
    movements.add(movement);
  }

  /**
   * Creates a Move with a list of Movement objects.  This constructor makes it easier to chain
   * multiple movements together.
   *
   * @param name the name of this move.
   * @param movements the Movements to run.
   */
  public Move(String name, List<Runnable> movements) {
    this.name = name;
    this.movements.addAll(movements);
  }

  /**
   * Runs the Movements in this Move.
   * @throws InterruptedException if the data could not be added to the send queue.
   */
  public void run() {
    Log.i(LOG_TAG, String.format("Running move %s.", name));
    for (Runnable movement : movements) {
      movement.run();
    }
  }
}
